home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / edit / jed207.lha / src / jed.lha / io.c < prev    next >
C/C++ Source or Header  |  1993-01-05  |  17KB  |  790 lines

  1.  
  2. /*
  3.  * IO.C
  4.  * (c) 1992-3 J.Harper
  5.  *
  6.  * functions for loading files, reading clips, etc
  7.  */
  8.  
  9. #include "jed.h"
  10. #include "jed_protos.h"
  11.  
  12. Prototype   BOOL    readtx        (TX *, STRPTR, LONG);
  13. Prototype   BOOL    writetx        (TX *, VW *, STRPTR);
  14. Prototype   VALUE * cmd_openfile    (LONG, VALUE *);
  15. Prototype   VALUE * cmd_savefileas  (LONG, VALUE *);
  16. Prototype   VALUE * cmd_savefile    (LONG, VALUE *);
  17. Prototype   VALUE * cmd_savesection (LONG, VALUE *);
  18. Prototype   VOID    doserror        (VOID);
  19. Prototype   VALUE * cmd_cd        (LONG, VALUE *);
  20. Prototype   VOID    killclipstuff   (VOID);
  21. Prototype   BOOL    writeclip        (LONG, POS *, POS *);
  22. Prototype   STRPTR  readclip        (LONG);
  23. Prototype   BOOL    writeline        (STRPTR, WORD, BPTR, VW *);
  24. Local        BOOL    dobackup        (STRPTR, VW *);
  25.  
  26. /* bytes to copy instead of tabs */
  27. Prototype   const UBYTE Spaces[];
  28. Prototype   const UBYTE Tabs[];
  29. const UBYTE Spaces[] = "                                                "
  30.                "                                                "
  31.                "                                                ";
  32. const UBYTE Tabs[] =   "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  33.  
  34. /*
  35.  * read a file into a tx structure, the line list should have been
  36.  * killed.
  37.  * I'm going to have to speed this up somehow.
  38.  * hopefully now loads lines of any length (upto max of 32768)
  39.  */
  40. #define SIZESTEP  50    /* size at which line list grows by */
  41. #define BUFFSTART 1024
  42. BOOL
  43. readtx(TX *tx, STRPTR fileName, LONG diskTab)
  44. {
  45.     BOOL rc = FALSE;
  46.     BPTR fh;
  47.     if(fileName && (*fileName) && (fh = Open(fileName, MODE_OLDFILE)))
  48.     {
  49.     STRPTR buff;
  50.     ULONG bufflen = BUFFSTART;
  51.     tx->tx_FileName = savestring(fileName);
  52.     tx->tx_TitleName = savestring(FilePart(fileName));
  53.  
  54.     if(buff = AllocVec(bufflen, 0L))
  55.     {
  56.         LONG c, i = 0;
  57.         LONG linenum = 0, allocedlines = 0;
  58.  
  59.         settitle("loading...");
  60.         while((c = FGetC(fh)) != -1)
  61.         {
  62.         if(i >= bufflen)
  63.         {
  64.             if(i >= 32768)
  65.             {
  66.             settitle("error: line too long (>32768)");
  67.             goto abort;
  68.             }
  69.             STRPTR newbuff = AllocVec(bufflen << 1, 0L);
  70.             if(!newbuff)
  71.             goto abortmem;
  72.             memcpy(newbuff, buff, i);
  73.             FreeVec(buff);
  74.             buff = newbuff;
  75.             bufflen <<= 1;
  76.         }
  77.         if(c == '\n')
  78.         {
  79.             STRPTR newstr;
  80.             LINE *line;
  81.             if(linenum >= allocedlines)
  82.             {
  83.             if(!resizelinelist(tx, SIZESTEP, linenum))
  84.                 goto abortmem;
  85.             allocedlines += SIZESTEP;
  86.             }
  87.             if(!(newstr = AllocVec(i + 1, 0L)))
  88.             goto abortmem;
  89.             memcpy(newstr, buff, i);
  90.             newstr[i] = 0;
  91.             line = tx->tx_Lines + linenum;
  92.             line->ln_Strlen = i + 1;
  93.             line->ln_Line = newstr;
  94.             i = 0;
  95.             linenum++;
  96.         }
  97.         else if(c == '\t')
  98.         {
  99.             WORD numspaces = diskTab - (i % diskTab);
  100.             if(i + numspaces >= bufflen)
  101.             {
  102.             STRPTR newbuff = AllocVec(bufflen << 1, 0L);
  103.             if(!newbuff)
  104.                 goto abortmem;
  105.             memcpy(newbuff, buff, i);
  106.             FreeVec(buff);
  107.             buff = newbuff;
  108.             bufflen <<= 1;
  109.             }
  110.             strncpy(buff + i, Spaces, numspaces);
  111.             i += numspaces;
  112.         }
  113.         else
  114.             buff[i++] = c;
  115.         }
  116.         if(i)
  117.         {
  118.         STRPTR newstr;
  119.         LINE *line;
  120.         if(!resizelinelist(tx, linenum - allocedlines + 1, linenum))
  121.             goto abortmem;
  122.         if(!(newstr = AllocVec(i + 1, 0L)))
  123.             goto abortmem;
  124.         memcpy(newstr, buff, i);
  125.         newstr[i] = 0;
  126.         line = tx->tx_Lines + linenum;
  127.         line->ln_Strlen = i + 1;
  128.         line->ln_Line = newstr;
  129.         linenum++;
  130.         }
  131.         else
  132.         if(!resizelinelist(tx, linenum - allocedlines, linenum))
  133.             goto abortmem;
  134.         tx->tx_Changes = 0;
  135.         rc = TRUE;
  136.         settitle("OK");
  137.         /* This block only gets executed if we aborted while
  138.          * reading the file.
  139.          */
  140.         if(0)
  141.         {
  142. abortmem:
  143.         settitle(NoMemMsg);
  144. abort:
  145.         clearlinelist(tx);
  146.         }
  147.         FreeVec(buff);
  148.     }
  149.     else
  150.         settitle(NoMemMsg);
  151.     Close(fh);
  152.     }
  153.     else
  154.     {
  155.     if(fileName && (*fileName))
  156.     {
  157.         tx->tx_FileName = savestring(fileName);
  158.         tx->tx_TitleName = savestring(FilePart(fileName));
  159.     }
  160.     else
  161.     {
  162.         tx->tx_FileName = savestring("");
  163.         tx->tx_TitleName = savestring("Untitled");
  164.     }
  165.     tx->tx_Changes = 0;
  166.     if(clearlinelist(tx))
  167.         rc = TRUE;
  168.     else
  169.         settitle(NoMemMsg);
  170.     }
  171.     return(rc);
  172. }
  173.  
  174. BOOL
  175. writetx(TX *tx, VW *vw, STRPTR fileName)
  176. {
  177.     BOOL rc = TRUE;
  178.     if(fileName)
  179.     {
  180.     BPTR fh = Open(fileName, MODE_NEWFILE);
  181.     if(fh)
  182.     {
  183.         LONG i;
  184.         LINE *line = tx->tx_Lines;
  185.         settitle("saving...");
  186.         for(i = 0; i < tx->tx_NumLines; i++, line++)
  187.         {
  188.         if(!writeline(line->ln_Line, line->ln_Strlen - 1, fh, vw))
  189.         {
  190.             doserror();
  191.             rc = FALSE;
  192.             break;
  193.         }
  194.         FPutC(fh, '\n');
  195.         }
  196.         Close(fh);
  197.     }
  198.     else
  199.     {
  200.         doserror();
  201.         rc = FALSE;
  202.     }
  203.     if(rc)
  204.         settitle("OK");
  205.     }
  206.     else
  207.     {
  208.     settitle(NoMemMsg);
  209.     rc = FALSE;
  210.     }
  211.     return(rc);
  212. }
  213.  
  214. /*
  215.  * (openfile `fileName')
  216.  */
  217. VALUE *
  218. cmd_openfile(LONG argc, VALUE *argv)
  219. {
  220.     if(TPLATE1(VTF_STRING))
  221.     {
  222.     VW *vw = CurrVW;
  223.     TX *tx = vw->vw_Tx;
  224.     BOOL rc = FALSE;
  225.     if((!tx->tx_Changes) || (ezreq("OK to lose %ld changes\nto file %s", "Yeah|Cancel", tx->tx_Changes, tx->tx_TitleName)))
  226.     {
  227.         killlinelist(tx);
  228.         freestring(tx->tx_FileName);
  229.         freestring(tx->tx_TitleName);
  230.         if(readtx(tx, ARG1.val_Value.String, vw->vw_Prefs.prf_DiskTab))
  231.         rc = TRUE;
  232.         else
  233.         clearlinelist(tx);  /* hope for some mem left */
  234.         setupfileprefs(tx);
  235.         updatedimensions(vw);
  236.         resetallviews(tx);
  237.     }
  238.     resetslptxtitles(tx);
  239.     setnumres(rc);
  240.     }
  241.     return(&RES);
  242. }
  243.  
  244. /*
  245.  * (savefileas `fileName')
  246.  */
  247. VALUE *
  248. cmd_savefileas(LONG argc, VALUE *argv)
  249. {
  250.     if(TPLATE1(VTF_STRING))
  251.     {
  252.     TX *tx = CurrVW->vw_Tx;
  253.     BOOL rc = FALSE;
  254.     dobackup(ARG1.val_Value.String, CurrVW);
  255.     if(writetx(tx, CurrVW, ARG1.val_Value.String))
  256.     {
  257.         freestring(tx->tx_FileName);
  258.         freestring(tx->tx_TitleName);
  259.         tx->tx_FileName = savestring(ARG1.val_Value.String);
  260.         tx->tx_TitleName = savestring(FilePart(ARG1.val_Value.String));
  261.         tx->tx_Changes = 0;
  262.         savefileprefs(tx);
  263.         rc = TRUE;
  264.     }
  265.     resetslptxtitles(tx);
  266.     setnumres(rc);
  267.     }
  268.     return(&RES);
  269. }
  270.  
  271. /*
  272.  * (savefile)
  273.  */
  274. VALUE *
  275. cmd_savefile(LONG argc, VALUE *argv)
  276. {
  277.     TX *tx = CurrVW->vw_Tx;
  278.     BOOL rc = FALSE;
  279.     if(tx->tx_FileName && tx->tx_FileName[0])
  280.     {
  281.     dobackup(tx->tx_FileName, CurrVW);
  282.     if(writetx(tx, CurrVW, tx->tx_FileName))
  283.     {
  284.         tx->tx_Changes = 0;
  285.         savefileprefs(tx);
  286.         rc = TRUE;
  287.     }
  288.     }
  289.     else
  290.     settitle("error: file is untitled");
  291.     setnumres(rc);
  292.     return(&RES);
  293. }
  294.  
  295. /*
  296.  * (savesection `sectionType' `fileName')
  297.  */
  298. VALUE *
  299. cmd_savesection(LONG argc, VALUE *argv)
  300. {
  301.     if(TPLATE2(VTF_STRING, VTF_STRING))
  302.     {
  303.     VW *vw = CurrVW;
  304.     POS endpos;
  305.     POS oldcurs = vw->vw_CursorPos;
  306.     BOOL rc = TRUE;
  307.     padcursor();
  308.     if(getsection(ARG1.val_Value.String, &endpos))
  309.     {
  310.         BPTR fh = Open(ARG2.val_Value.String, MODE_NEWFILE);
  311.         if(fh)
  312.         {
  313.         LINE *line = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  314.         if(endpos.pos_Line == vw->vw_CursorPos.pos_Line)
  315.         {
  316.             if(!writeline(line->ln_Line + vw->vw_CursorPos.pos_Col, endpos.pos_Col - vw->vw_CursorPos.pos_Col, fh, vw))
  317.             {
  318.             doserror();
  319.             rc = FALSE;
  320.             }
  321.         }
  322.         else
  323.         {
  324.             if(vw->vw_CursorPos.pos_Col)
  325.             {
  326.             if(!writeline(line->ln_Line + vw->vw_CursorPos.pos_Col, line->ln_Strlen - vw->vw_CursorPos.pos_Col - 1, fh, vw))
  327.                 goto writeerr;
  328.             FPutC(fh, '\n');
  329.             vw->vw_CursorPos.pos_Line++;
  330.             line++;
  331.             }
  332.             while(vw->vw_CursorPos.pos_Line < endpos.pos_Line)
  333.             {
  334.             if(!writeline(line->ln_Line, line->ln_Strlen - 1, fh, vw))
  335.                 goto writeerr;
  336.             FPutC(fh, '\n');
  337.             vw->vw_CursorPos.pos_Line++;
  338.             line++;
  339.             }
  340.             if(endpos.pos_Col)
  341.             {
  342.             if(!writeline(line->ln_Line, endpos.pos_Col, fh, vw))
  343.             {
  344. writeerr:            doserror();
  345.                 rc = FALSE;
  346.             }
  347.             }
  348.         }
  349.         Close(fh);
  350.         }
  351.         else
  352.         {
  353.         doserror();
  354.         rc = FALSE;
  355.         }
  356.     }
  357.     vw->vw_CursorPos = oldcurs;
  358.     setnumres(rc);
  359.     }
  360.     return(&RES);
  361. }
  362.  
  363. /*
  364.  * Sets title bar to message describing previous DOS error.
  365.  */
  366. VOID
  367. doserror(VOID)
  368. {
  369.     UBYTE errmsg[81];
  370.     if(Fault(IoErr(), "DOS error", errmsg, 81))
  371.     settitle(errmsg);
  372.     else
  373.     settitlefmt("DOS error: %ld", IoErr());
  374. }
  375.  
  376. /*
  377.  * (cd `dir')
  378.  */
  379. VALUE *
  380. cmd_cd(LONG argc, VALUE *argv)
  381. {
  382.     if(TPLATE1(VTF_STRING))
  383.     {
  384.     BOOL rc = FALSE;
  385.     BPTR lock = Lock(ARG1.val_Value.String, SHARED_LOCK);
  386.     if(lock)
  387.     {
  388.         lock = CurrentDir(lock);
  389.         UnLock(lock);
  390.         rc = TRUE;
  391.     }
  392.     else
  393.         settitlefmt("can't lock %s", (LONG)ARG1.val_Value.String);
  394.     setnumres(rc);
  395.     }
  396.     return(&RES);
  397. }
  398.  
  399. /*
  400.  * IFF code, adapted from the newiff/other/clipftxt.c example on the 2.0
  401.  * native developer set.
  402.  */
  403.  
  404. #define ID_FTXT     MAKE_ID('F','T','X','T')
  405. #define ID_CHRS     MAKE_ID('C','H','R','S')
  406.  
  407. Local const STRPTR IFFErrorMsgs[] =
  408. {
  409.     "End of file.",
  410.     "End of context.",
  411.     "No lexical scope.",
  412.     "No memory.",
  413.     "Stream read error.",
  414.     "Stream write error.",
  415.     "Stream seek error.",
  416.     "File is corrupt.",
  417.     "IFF syntax error.",
  418.     "Not an IFF file.",
  419.     "Required call-back hook missing.",
  420.     "Return to client."
  421. };
  422.  
  423.     APTR   IFFParseBase;
  424. Local    STRPTR InternalClip;
  425. Local    LONG   IClipLen;    /* not including zero terminator */
  426.  
  427. VOID
  428. killclipstuff(VOID)
  429. {
  430.     freestring(InternalClip);
  431.     InternalClip = NULL;
  432.     IClipLen = 0;
  433.     if(IFFParseBase)
  434.     {
  435.     CloseLibrary(IFFParseBase);
  436.     IFFParseBase = NULL;
  437.     }
  438. }
  439.  
  440. /*
  441.  * Writes a section of text to the clipboard, *startPos IS trashed (it will
  442.  * point to the end of the copied section (maybe)).
  443.  * if unit is less than 0 the text is copied to my internal clipboard.
  444.  */
  445. BOOL
  446. writeclip(LONG unit, POS *startPos, POS *endPos)
  447. {
  448.     if(unit < 0)
  449.     {
  450.     IClipLen = sectionlength(startPos, endPos);
  451.     freestring(InternalClip);
  452.     if(InternalClip = AllocVec(IClipLen + 1, 0L))
  453.     {
  454.         copysection(startPos, endPos, InternalClip);
  455.         InternalClip[IClipLen] = 0;
  456.         return(TRUE);
  457.     }
  458.     settitle(NoMemMsg);
  459.     return(FALSE);
  460.     }
  461.     else if(IFFParseBase || (IFFParseBase = OpenLibrary("iffparse.library", 36)))
  462.     {
  463.     struct IFFHandle *iff;
  464.     LONG error = 0;
  465.     if(iff = AllocIFF())
  466.     {
  467.         if(iff->iff_Stream = (ULONG)OpenClipboard(unit))
  468.         {
  469.         InitIFFasClip(iff);
  470.         if(!(error = OpenIFF(iff, IFFF_WRITE)))
  471.         {
  472.             if(!(error = PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)))
  473.             {
  474.             if(!(error = PushChunk(iff, 0, ID_CHRS, IFFSIZE_UNKNOWN)))
  475.             {
  476.                 LINE *line = CurrVW->vw_Tx->tx_Lines + startPos->pos_Line;
  477.                 LONG writelen;
  478.                 if(endPos->pos_Line == startPos->pos_Line)
  479.                 {
  480.                 writelen = endPos->pos_Col - startPos->pos_Col;
  481.                 if(WriteChunkBytes(iff, line->ln_Line + startPos->pos_Col, writelen) != writelen)
  482.                     error = IFFERR_WRITE;
  483.                 }
  484.                 else
  485.                 {
  486.                 if(startPos->pos_Col)
  487.                 {
  488.                     writelen = line->ln_Strlen - startPos->pos_Col - 1;
  489.                     if(WriteChunkBytes(iff, line->ln_Line + startPos->pos_Col, writelen) != writelen)
  490.                     goto writeerr;
  491.                     if(WriteChunkBytes(iff, "\n", 1) != 1)
  492.                     goto writeerr;
  493.                     startPos->pos_Line++;
  494.                     line++;
  495.                 }
  496.                 while(startPos->pos_Line < endPos->pos_Line)
  497.                 {
  498.                     writelen = line->ln_Strlen - 1;
  499.                     if(WriteChunkBytes(iff, line->ln_Line, writelen) != writelen)
  500.                     goto writeerr;
  501.                     if(WriteChunkBytes(iff, "\n", 1) != 1)
  502.                     goto writeerr;
  503.                     startPos->pos_Line++;
  504.                     line++;
  505.                 }
  506.                 if(endPos->pos_Col)
  507.                 {
  508.                     writelen = endPos->pos_Col;
  509.                     if(WriteChunkBytes(iff, line->ln_Line, writelen) != writelen)
  510.                     {
  511. writeerr:
  512.                     error = IFFERR_WRITE;
  513.                     }
  514.                 }
  515.                 }
  516.                 if(!error)
  517.                 error = PopChunk(iff);
  518.                 else
  519.                 PopChunk(iff);
  520.             }
  521.             if(!error)
  522.                 error = PopChunk(iff);
  523.             else
  524.                 PopChunk(iff);
  525.             }
  526.             CloseIFF(iff);
  527.         }
  528.         CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
  529.         }
  530.         else
  531.         error = IFFERR_NOMEM;    /* ?? */
  532.         FreeIFF(iff);
  533.     }
  534.     else
  535.         error = IFFERR_NOMEM;
  536.  
  537.     CloseLibrary(IFFParseBase);
  538.     IFFParseBase = NULL;
  539.  
  540.     if(error)
  541.     {
  542.         settitlefmt("clip error: %s", (LONG)IFFErrorMsgs[-error - 1]);
  543.         return(FALSE);
  544.     }
  545.     return(TRUE);
  546.     }
  547.     settitle("need iffparse.library");
  548.     return(FALSE);
  549. }
  550.  
  551. /*
  552.  * result should be FreeVec()'ed after use if non-NULL. A unit of -1
  553.  * reads the internal clip.
  554.  *
  555.  * note:
  556.  *  Currently this only reads the first CHRS chunk that it finds.
  557.  */
  558. STRPTR
  559. readclip(LONG unit)
  560. {
  561.     STRPTR text = NULL;
  562.     if(unit < 0)
  563.     {
  564.     if(IClipLen)
  565.     {
  566.         if(text = AllocVec(IClipLen + 1, 0L))
  567.         {
  568.         memcpy(text, InternalClip, IClipLen);
  569.         text[IClipLen] = 0;
  570.         }
  571.         else
  572.         settitle(NoMemMsg);
  573.     }
  574.     else
  575.         settitle("error: nothing on internal clipboard");
  576.     }
  577.     else if(IFFParseBase || (IFFParseBase = OpenLibrary("iffparse.library", 36)))
  578.     {
  579.     struct IFFHandle *iff;
  580.     LONG error;
  581.     if(iff = AllocIFF())
  582.     {
  583.         if(iff->iff_Stream = (ULONG)OpenClipboard(unit))
  584.         {
  585.         InitIFFasClip(iff);
  586.         if(!(error = OpenIFF(iff, IFFF_READ)))
  587.         {
  588.             if(!(error = StopChunk(iff, ID_FTXT, ID_CHRS)))
  589.             {
  590.             struct ContextNode *cn;
  591.             if(!(error = ParseIFF(iff, IFFPARSE_SCAN)))
  592.             {
  593.                 cn = CurrentChunk(iff);
  594.                 if(cn && (cn->cn_Type == ID_FTXT) && (cn->cn_ID == ID_CHRS))
  595.                 {
  596.                 if(text = AllocVec(cn->cn_Size + 1, 0L))
  597.                 {
  598.                     error = ReadChunkBytes(iff, text, cn->cn_Size);
  599.                     if(error > 0)
  600.                     {
  601.                     text[error] = 0;
  602.                     error = 0;
  603.                     }
  604.                 }
  605.                 else
  606.                     error = IFFERR_NOMEM;
  607.                 }
  608.                 else
  609.                 error = IFFERR_NOTIFF;    /* ?? */
  610.             }
  611.             }
  612.             CloseIFF(iff);
  613.         }
  614.         CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
  615.         }
  616.         else
  617.         error = IFFERR_NOMEM;
  618.         FreeIFF(iff);
  619.     }
  620.     else
  621.         error = IFFERR_NOMEM;
  622.     if(error)
  623.     {
  624.         if(text)
  625.         {
  626.         FreeVec(text);
  627.         text = NULL;
  628.         }
  629.         settitlefmt("clip error: %s", (LONG)IFFErrorMsgs[-error - 1]);
  630.     }
  631.     CloseLibrary(IFFParseBase);
  632.     IFFParseBase = NULL;
  633.     }
  634.     else
  635.     settitle("need iffparse.library");
  636.     return(text);
  637. }
  638.  
  639. /*
  640.  * Writes out a line of text,
  641.  * if SaveTabs == 1 leading spaces will be changed to tabs,
  642.  * if SaveTabs == 2 all spaces (except after quotes) are made into tabs and
  643.  * trailing spaces are discarded.
  644.  */
  645. BOOL
  646. writeline(STRPTR line, WORD len, BPTR fh, VW *vw)
  647. {
  648.     if(vw->vw_Prefs.prf_SaveTabs)
  649.     {
  650.     WORD lastchg = 0;
  651.     BOOL inspc = FALSE;
  652.     BOOL nodo = FALSE;
  653.     LONG disktab = vw->vw_Prefs.prf_DiskTab;
  654.     WORD i;
  655.     UBYTE c;
  656.     for(i = 0; (i <= len) && (c = line[i]); i++)
  657.     {
  658.         if(!nodo)
  659.         {
  660.         if(c == ' ')
  661.         {
  662.             if(!inspc)
  663.             {
  664.             if(FWrite(fh, line + lastchg, 1, i - lastchg) != i - lastchg)
  665.                 goto error;
  666.             lastchg = i;
  667.             inspc = TRUE;
  668.             }
  669.         }
  670.         else
  671.         {
  672.             if(inspc)
  673.             {
  674.             WORD numtabs, numspcs;
  675.             if(lastchg == i - 1)
  676.             {
  677.                 numtabs = 0;
  678.                 numspcs = 1;
  679.             }
  680.             else
  681.             {
  682.                 numtabs = (i - (lastchg - (lastchg % disktab))) / disktab;
  683.                 numspcs = i % disktab;
  684.                 if(numspcs > i - lastchg)
  685.                 numspcs = i - lastchg;
  686.             }
  687.             if(FWrite(fh, Tabs, 1, numtabs) != numtabs)
  688.                 goto error;
  689.             if(FWrite(fh, Spaces, 1, numspcs) != numspcs)
  690.                 goto error;
  691.             lastchg = i;
  692.             inspc = FALSE;
  693.             }
  694.             if((c == '"') || (c == '\'') || (c == '`') || (vw->vw_Prefs.prf_SaveTabs == 1))
  695.             nodo = TRUE;
  696.         }
  697.         }
  698.     }
  699.     if((!inspc) || nodo)
  700.     {
  701.         if(FWrite(fh, line + lastchg, 1, i - lastchg) != i - lastchg)
  702.         goto error;
  703.     }
  704.     return(TRUE);
  705.     }
  706.     else
  707.     {
  708.     if(FWrite(fh, line, 1, len) == len)
  709.         return(TRUE);
  710.     }
  711. error:
  712.     return(FALSE);
  713. }
  714.  
  715. /*
  716.  * Sorts out backup files.
  717.  * Backups are saved to the directory set by (setpref `bakdir'). The
  718.  * number of backups kept is determined by (setpref `baknum').
  719.  * for a file called `foo' it's backups would be something like this,
  720.  *  t:foo.bak1
  721.  *  t:foo.bak2
  722.  *  t:foo.bakN
  723.  */
  724. #define COPYSTEP 65536
  725. Local BOOL
  726. dobackup(STRPTR fileName, VW *vw)
  727. {
  728.     BOOL rc = TRUE;
  729.     if(vw->vw_Prefs.prf_MaxBak > 0)
  730.     {
  731.     UBYTE namebuff[110];
  732.     WORD i;
  733.     BPTR srcfh = 0, dstfh = 0;
  734.     strcpy(namebuff, vw->vw_Prefs.prf_BakDir);
  735.     if(AddPart(namebuff, FilePart(fileName), 100))
  736.     {
  737.         for(i = vw->vw_Prefs.prf_MaxBak - 1; i; i--)
  738.         {
  739.         UBYTE srcbuff[110];
  740.         UBYTE dstbuff[110];
  741.         sprintf(srcbuff, "%s.bak%ld", namebuff, i);
  742.         sprintf(dstbuff, "%s.bak%ld", namebuff, i + 1);
  743.         DeleteFile(dstbuff);
  744.         Rename(srcbuff, dstbuff);
  745.         }
  746.     }
  747.     else
  748.     {
  749.         settitle("error: backup directory name too long");
  750.         return(FALSE);
  751.     }
  752.     strcat(namebuff, ".bak1");
  753.     if((srcfh = Open(fileName, MODE_OLDFILE)) && (dstfh = Open(namebuff, MODE_NEWFILE)))
  754.     {
  755.         STRPTR copybuff;
  756.         if(copybuff = AllocVec(COPYSTEP, 0L))
  757.         {
  758.         LONG actual;
  759.         do
  760.         {
  761.             if((actual = Read(srcfh, copybuff, COPYSTEP)) < 0)
  762.             {
  763.             doserror();
  764.             rc = FALSE;
  765.             break;
  766.             }
  767.             if(Write(dstfh, copybuff, actual) != actual)
  768.             {
  769.             doserror();
  770.             rc = FALSE;
  771.             break;
  772.             }
  773.         }
  774.         while(actual == COPYSTEP);
  775.         FreeVec(copybuff);
  776.         }
  777.         else
  778.         {
  779.         settitle(NoMemMsg);
  780.         rc = FALSE;
  781.         }
  782.     }
  783.     if(dstfh)
  784.         Close(dstfh);
  785.     if(srcfh)
  786.         Close(srcfh);
  787.     }
  788.     return(rc);
  789. }
  790.